#!/usr/bin/env python3.0

import sys
if sys.version_info[0] != 3:
    print('This program requires Python 3.x version')
    sys.exit()

import os.path
import curses
import calendar
import datetime

import locale
locale.setlocale(locale.LC_ALL,"")
encoding = locale.getpreferredencoding()

import gettext
localedir = sys.argv[0] if __name__ == '__main__' else __file__
localedir = os.path.abspath(os.path.dirname(localedir)) + "/locale"
gettext.install('laikas', localedir)


MONTH_NAME = ['',
    _('January'),
    _('February'),
    _('March'),
    _('April'),
    _('May'),
    _('June'),
    _('July'),
    _('August'),
    _('September'),
    _('October'),
    _('November'),
    _('December')
]




def init_colors():
    global ATTR_WEEK_TITLE
    global ATTR_WEEKEND_TITLE
    global ATTR_MONTH_TITLE
    global ATTR_TODAY_TITLE

    curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
    ATTR_WEEK_TITLE = curses.color_pair(1) | curses.A_BOLD

    curses.init_pair(2, curses.COLOR_WHITE, curses.COLOR_YELLOW)
    ATTR_WEEKEND_TITLE = curses.color_pair(2) | curses.A_BOLD

    curses.init_pair(3, curses.COLOR_WHITE, curses.COLOR_BLACK)
    ATTR_MONTH_TITLE = curses.color_pair(3) | curses.A_BOLD

    curses.init_pair(4, curses.COLOR_WHITE, curses.COLOR_GREEN)
    ATTR_TODAY_TITLE = curses.color_pair(4) | curses.A_BOLD


class MonthCalendar():

    def __init__(self):
        self.week_first_day = calendar.MONDAY
        self.today = datetime.date.today()

    def set_window(self, win):
        self.win = win
        (self.maxy, self.maxx) = self.win.getmaxyx()

    def find_first_day(self):
        """Sets self.date to first day of week"""

        oneday = datetime.timedelta(days=1)
        while self.date.weekday() != self.week_first_day:
            self.date -= oneday

    def get_week_titles(self):
        if (len(" ".join(calendar.day_name)) < self.maxx):
            return calendar.day_name
        else:
            return calendar.day_abbr


    def show_day(self, h, w, y, x):
        """Draws one day box of a moth."""

        if y+1 < self.maxy:
            if self.date == self.today:
                attr = ATTR_TODAY_TITLE
            elif self.date.weekday() in (calendar.SATURDAY, calendar.SUNDAY):
                attr = ATTR_WEEKEND_TITLE
            else:
                attr = ATTR_WEEK_TITLE

            title = "%d " % (self.date.day)
            self.win.addstr(y, x, title.rjust(w), attr)


    def show_month(self, h, w, y, x):
        """Draws month title"""

        if y+1 < self.maxy:
            title = " %d, %s" % (self.date.year, MONTH_NAME[self.date.month])
            self.win.addstr(y, x, title.ljust(w), ATTR_MONTH_TITLE)


    def render(self, date):
        """Renders all months calendar."""

        self.date = date
        self.current_date = date
        self.find_first_day()

        daywin_width = (self.maxx-6) // 7

        # Show week titles
        (x, remainder) = (0, (self.maxx-6) % 7)
        week_titles = self.get_week_titles()
        for i in range(7):
            width = daywin_width + (1 if remainder > 0 else 0)
            self.win.addstr(0, x, week_titles[i].center(width))
            x = x + daywin_width + 1 + (1 if remainder > 0 else 0)
            remainder = remainder - 1

        # Show month title
        self.show_month(1, self.maxx, 1, 0)

        # Show all days of a week
        oneday = datetime.timedelta(days=1)
        y = 3
        while y+2 < self.maxy:
            x = 0
            remainder = (self.maxx-6) % 7
            for i in range(7):
                width = daywin_width + (1 if remainder > 0 else 0)
                if y+2 > self.maxy: y += 2; break
                self.show_day(2, width, y, x)
                x += daywin_width + 1 + (1 if remainder > 0 else 0)

                month = self.date.month
                self.date += oneday
                if month != self.date.month:
                    if y+2 > self.maxy: y += 2; break
                    self.show_month(1, self.maxx, y+2, 0)
                    y += 3 if i != 6 else 1

                remainder -= 1
            y += 2

        self.win.refresh()


    def handle_input(self, key):
        if key in [curses.KEY_DOWN, 66]:
            self.win.erase()
            self.current_date += datetime.timedelta(weeks=1)
            self.render(self.current_date)

        elif key in [curses.KEY_UP, 65]:
            self.win.erase()
            self.current_date -= datetime.timedelta(weeks=1)
            self.render(self.current_date)


def handle_input(key):

    if key == curses.KEY_RESIZE:
        stdscr.clear()
        crview.set_window(stdscr)
        crview.render(datetime.date.today())

    elif key in [curses.KEY_UP, curses.KEY_DOWN, 66, 65]:
        crview.handle_input(key)

    elif key == ord('q'):
        return False

    # stdscr.addstr(0, 0, str(key).ljust(10))
    # stdscr.addstr(1, 0, str(curses.KEY_DOWN).ljust(10))

    return True


def main(win):
    global stdscr, crview
    stdscr = win
    curses.curs_set(0)

    init_colors()
    stdscr.refresh()

    crview = MonthCalendar()
    crview.set_window(stdscr)
    crview.render(datetime.date.today())

    while handle_input(stdscr.getch()):
        pass



if __name__ == '__main__':
    curses.wrapper(main)

